package ufpb.compiladores.lexico.run;

import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ufpb.compiladores.lexico.Automaton;
import ufpb.compiladores.lexico.AutomatonFactory;
import ufpb.compiladores.lexico.Enviroment;
import ufpb.compiladores.lexico.Reader;
import ufpb.compiladores.lexico.XMLLoader;
import ufpb.compiladores.lexico.run.GUI.CallTables;
import ufpb.compiladores.lexico.run.GUI.SelectFiles;

/**
 *
 * @author seminick
 */
public class RunLexico {

    private enum OutType {
        
        GUI,
        FILE,
        CONSOLE,
        HTML
    }
    
    public static void main(String[] args) {

        File conf = null;
        LinkedList<File> sources = new LinkedList<File>();
        File out = null;
        OutType ot = OutType.CONSOLE;
        
        for (String arg : args) {
            
            if (arg.matches("--conf=.+")) {
                
                String[] parts = arg.split("=");
                conf = new File(parts[1]);
            } else if(arg.matches("--source=.+")) {
                
                String[] parts = arg.split("=");
                sources.add(new File(parts[1]));
            } else if(arg.matches("--out=.+")) {
                
                String[] parts = arg.split("=");
                out = new File(parts[1]);
            } else if(arg.matches("--outtype=.+")) {
                
                String[] parts = arg.split("=");
                if (parts[1].equals("GUI")) {
                    
                    ot = OutType.GUI;
                } else if (parts[1].equals("FILE")) {
                    
                    ot = OutType.FILE;
                } else if (parts[1].equals("CONSOLE")) {
                    
                    ot = OutType.CONSOLE;
                } else if (parts[1].equals("HTML")) {
                    
                    ot = OutType.HTML;
                } else {
                    
                    System.out.println("[ERROR] Unkown outtype value " + parts[1]);
                    usage();
                    System.exit(1);
                }
            } else {
                 
                System.out.println("[WARNING] Ignoring unkown parameter: " + arg);
            }
        }
        
        if (conf == null) {
            
            System.out.println("[ERROR] Missing configuration file");
            usage();
            System.exit(1);
        } else if (ot == OutType.FILE && out == null) {
            
            System.out.println("[ERROR] You must specify a out file when saving output to a file."
                    + " or use --outtype=GUI");
            usage();
            System.exit(1);
        } else if (ot == OutType.HTML && out == null) {
            
            System.out.println("[ERROR] You must specify a out file when saving output to HTML."
                    + " or use --outtype=GUI");
            usage();
            System.exit(1);
        }
        
        System.out.println("Creating enviroment with: " + conf.getAbsolutePath());
        try {
            
            XMLLoader load = new XMLLoader(conf);
            Enviroment env = load.createEnviroment();
            Document outdoc = DocumentBuilderFactoryImpl.newInstance()
                        .newDocumentBuilder().newDocument();
            Element r = outdoc.createElement("Raiz");
            if (ot == OutType.GUI) {
                
                if (sources.size() == 0) {
                    
                    (new SelectFiles()).setVisible(true);
                } else {
                    
                    File[] sf = sources.toArray(new File[0]);
                    Document[] docs = new Document[sf.length];
                    for (int i = 0; i < sf.length; i++) {
                        
                        Automaton a = AutomatonFactory.getAutomaton(env, new Reader(sf[i]));
                        a.generateTable(outdoc, r);
                    }
                    (new CallTables(docs, sf)).setVisible(true);
                }
            } else {
                
                for (File source : sources) {

                    if (source.exists()) {

                        try {

                            Reader sr = new Reader(source);
                            Automaton auto = AutomatonFactory.getAutomaton(env, sr);
                            auto.generateTable(outdoc, r);
                            Transformer tf = TransformerFactory.newInstance().newTransformer();
                            //tf.setOutputProperty(OutputKeys., null);
                            tf.setOutputProperty(OutputKeys.INDENT, "yes");
                            DOMSource docs = new DOMSource(outdoc);
                            switch (ot) {

                                case FILE:

                                    //StringWriter sw = new StringWriter();
                                    FileOutputStream outs = new FileOutputStream(out);
                                    StreamResult srr = new StreamResult(outs);
                                    tf.transform(docs, srr);
                                    outs.flush();
                                    outs.close();
                                    break;
                                case CONSOLE:

                                    //System.out.println(outdoc.toString());
                                    StreamResult srrc = new StreamResult(System.out);
                                    tf.transform(docs, srrc);
                                    break;

                                case HTML:

                                    String html = HtmlGenerator.generateHtml(outdoc, source);
                                    FileOutputStream fos = new FileOutputStream(out);
                                    fos.write(html.getBytes());
                                    fos.flush();
                                    fos.close();
                                    break;
                            }
                            sr.close();
                        } catch (IOException ioe) {

                            System.out.println("[ERROR] IO Error when processing "
                                    + source.getAbsolutePath());
                        }
                    } else {

                        System.out.println("[WARNING] File not found: " +  source.getAbsolutePath());
                    }
                    
                    System.exit(0);
                }
            }
        } catch (Exception e) {
            
            System.out.println("[ERROR] An error occured with msg:");
            System.out.println(e.getMessage());
            //e.printStackTrace();
            System.exit(1);
        }
    }
    
    private static void usage() {
        
        System.out.println("[INFO] Lexical analyzer:");
        System.out.println("Projeto de compiladores UFPB 2011.2");
        System.out.println("Developers: José Ivan, Sarah Soares");
        System.out.println("--conf=FILE Configuration file");
        System.out.println("--out=FILE File to put output if --outtype=FILE");
        System.out.println("--outtype=FILE|GUI|CONSOLE|HTML Output type. CONSOLE is default");
        System.out.println("--source=FILE Source file to be processed. Multiple files can be passed.");
        System.out.println("--source=FILE1 --source=FILE2 --source=FILE3");
    }
}
